package com.heima.search.service.impl;

import cn.hutool.core.util.StrUtil;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.search.dto.UserSearchDto;
import com.heima.model.search.pojo.ApAssociateWords;
import com.heima.model.search.pojo.ApUserSearch;
import com.heima.search.model.Trie;
import com.heima.search.service.ApAssociateWordsService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.lang.ref.SoftReference;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author TheCai
 * @date 2021/6/9 21:43
 */
@Service
public class ApAssociateWordsServiceImpl implements ApAssociateWordsService, InitializingBean {

  @Autowired MongoTemplate mongoTemplate;

  /**
   * 联想词
   *
   * @param dto
   * @return
   */
  @Override
  public ResponseResult findAssociate(UserSearchDto dto) {

    if (StrUtil.isEmpty(dto.getSearchWords())) {
      return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
    }

    List<ApAssociateWords> wordsList =
        mongoTemplate.find(
            Query.query(Criteria.where("associateWords").regex(".*" + dto.getSearchWords() + ".*")),
                ApAssociateWords.class);

    return ResponseResult.okResult(wordsList);
  }


  //公有变量
  //变量引用有四种类型:  强引用  ,  软引用(内存不足的时候,释放掉)  , 弱引用(随时可能被是释放)  虚引用(得不到状态)
  public static SoftReference<Trie> softReference;
  /**
   * 模糊查询第二种方法
   * @param userSearchDto
   * @return
   */
  @Override
  public ResponseResult findAssociateV2(UserSearchDto userSearchDto) {
    //当项目启动时, 初始胡Trie数
    Trie trie = softReference.get();
    if (trie==null){
      initTrieData();
    }
    //查询联系词  从Trie树中包含的联想词
    List<String> dataList = trie.getData(userSearchDto.getSearchWords());
    List<ApAssociateWords> associateWordsList = dataList.stream().map(str -> {
      ApAssociateWords words = new ApAssociateWords();
      words.setAssociateWords(str);
      return words;
    }).collect(Collectors.toList());
    //返回结果
    return ResponseResult.okResult(associateWordsList);
  }

  public void initTrieData(){
    List<ApAssociateWords> list = mongoTemplate.findAll(ApAssociateWords.class);

    Trie trie = new Trie();
    //将所有联系词  存入到Trie树中
    list.stream().map(ApAssociateWords::getAssociateWords).forEach(trie::insert);


    softReference=new SoftReference<Trie>(trie);


  }

  /**
   * 只要这个方法一调用就只执行这个方法
   * @throws Exception
   */
  @Override
  public void afterPropertiesSet() throws Exception {
    //当前spring实例准备完毕后  执行的初始化方法
    initTrieData();
  }
}
